# -*- coding: utf-8 -*-

import json
import logging
from datetime import datetime

from common.bankcard.handler import today_cash_flow_alert
from common.mch import db as mch_db
from common.mch import handler as mch_handler
from common.order_withdraw import db as order_withdraw_db
from common.order_withdraw import handler as order_withdraw_handler
from common.order_withdraw.db import ORDER_STATUS
from common.bankcard import db as bankcard_db
from common.utils import exceptions as err
from common.utils.api import check_params, get_client_ip
from common.utils.decorator import response_wrapper
from django.utils.encoding import smart_unicode
from django.views.decorators.http import require_POST

_LOGGER = logging.getLogger('hydra')


@require_POST
@response_wrapper
def order_withdraw_create(request):
    params = json.loads(smart_unicode(request.body))
    #params = request.POST.dict()
    _LOGGER.info('create order withdraw: %s', json.dumps(params))
    check_params(params, [
        'mch_id', 'mch_order_no', 'player_id', 'bank', 'account_name',
        'account_number', 'amount', 'notify_url', 'sign'
    ])
    validate_status = mch_handler.validate_mch(params['mch_id'])
    if not validate_status:
        raise err.AuthenticateError('mch is_inactive')
    sign = params['sign']
    params.pop('sign')
    mch_id = params['mch_id']
    calculated_sign = mch_handler.generate_sign(mch_id, params)
    if sign != calculated_sign:
        raise err.AuthenticateError('sign error')
    params['mch_create_ip'] = get_client_ip(request)
    params.update(sign=sign)

    mch_order_exists = order_withdraw_db.mch_order_no_exist(
        params['mch_order_no'])

    if mch_order_exists:
        raise err.ResourceNotFound('mch_order_no already exists')

    mch = mch_db.get_mch(mch_id)
    if not mch:
        raise err.ResourceNotFound('mch_id {} cannot be found'.format(mch_id))

    selected_card, message, log_message = order_withdraw_handler.select_card_for_wirthdraw(
        mch.name, params['amount'])
    if not selected_card:
        no_card_error = 'mch_order_no {} error {}'.format(
            params['mch_order_no'], message)
        no_card_error_log = 'mch_order_no {} error {}'.format(
            params['mch_order_no'], log_message)
        _LOGGER.info('create order withdraw error: %s', no_card_error_log)
        raise err.ResourceNotFound(no_card_error)

    order_withdraw_handler.frequency_alert(selected_card, request.META['HTTP_HOST'])
    today_cash_flow_alert(selected_card, request.META['HTTP_HOST'])

    order = order_withdraw_db.create_order(params,
                                           selected_card.account_holder,
                                           selected_card.account_number,
                                           selected_card.bank,
                                           selected_card.name)

    return {
        'result': 'ok',
        'order_id': order.id,
        'mch_order_no': order.mch_order_no,
        'status': ORDER_STATUS.get_key(order.status)
    }


@require_POST
@response_wrapper
def order_withdraw_query(request):
    _LOGGER.info('query order request: %s', request.body)
    params = json.loads(smart_unicode(request.body))
    check_params(params, ['mch_id', 'mch_order_no', 'sign'])
    sign = params['sign']
    params.pop('sign')
    mch_id = params['mch_id']
    calculated_sign = mch_handler.generate_sign(mch_id, params)
    if sign != calculated_sign:
        raise err.AuthenticateError('sign error')

    params.update(sign=sign)
    order = order_withdraw_db.get_mch_order_no(params['mch_order_no'])

    if not order:
        raise err.ResourceNotFound('mch_order_no {} does not exists'.format(
            params['mch_order_no']))

    bankcard = bankcard_db.get_bankcard_by_name(order.source_card_code)
    account_number, card_balance = (bankcard.account_number,
                                    bankcard.balance) if bankcard else ("",
                                                                        0.00)

    return {
        'result': 'ok',
        'order_id': order.id,
        'mch_order_no': order.mch_order_no,
        'status': ORDER_STATUS.get_key(order.status),
        'account_number': account_number,
        'card_balance': card_balance
    }


@require_POST
@response_wrapper
def order_withdraw_edit(request):
    _LOGGER.info('edit order withdraw: %s', request.body)
    params = json.loads(smart_unicode(request.body))
    check_params(
        params,
        ['order_id', 'status', 'notes', 'updated_by', 'operating_time'])

    order_id = params['order_id']
    if order_withdraw_handler.check_valid_order(
            params, order_withdraw_handler.order_withdraw_finished):
        order_withdraw_db.edit_order(params)
        if str(order_id)[0:1] == '1':
            order_withdraw_handler.notify({'order_id': order_id})

    return {'result': 'ok'}


@require_POST
@response_wrapper
def order_withdraw_push(request):
    _LOGGER.info('push order withdraw: %s', request.body)
    params = json.loads(smart_unicode(request.body))
    check_params(params, ['order_id', 'updated_by'])
    order_id = params['order_id']
    status_msg = 'order_id {} is still'.format(order_id)
    if order_withdraw_handler.check_valid_order(
            params, order_withdraw_handler.order_withdraw_not_finished,
            status_msg):
        order_withdraw_handler.notify(params)

    return {'result': 'ok'}


@require_POST
@response_wrapper
def order_withdraw_exe_lock(request):
    _LOGGER.info('order_withdraw_exe_lock order withdraw: %s', request.body)
    params = json.loads(smart_unicode(request.body))
    check_params(params, ['order_id', 'exe_locked'])
    order_id = params['order_id']
    if order_withdraw_handler.check_valid_order(
            params, order_withdraw_handler.order_withdraw_not_processing):
        params.pop('order_id')
        order_withdraw_db.upsert_order_withdraw(params, order_id)

    return {'result': 'ok'}


@require_POST
@response_wrapper
def order_withdraw_show_ukey(request):
    _LOGGER.info('order_withdraw_show_ukey order withdraw: %s', request.body)
    params = json.loads(smart_unicode(request.body))
    check_params(params, ['order_id', 'show_ukey'])
    order_id = params['order_id']
    if order_withdraw_handler.check_valid_order(
            params, order_withdraw_handler.order_withdraw_not_processing):
        params.pop('order_id')
        params['status'] = ORDER_STATUS.PAYING
        order_withdraw_db.upsert_order_withdraw(params, order_id)
    return {'result': 'ok'}


@require_POST
@response_wrapper
def order_withdraw_auto_invalid(request):
    _LOGGER.info('order_withdraw_auto_invalid order withdraw: %s',
                 request.body)
    order_withdraw_handler.auto_invalid()
    return {'result': 'ok'}


@require_POST
@response_wrapper
def order_withdraw_retry_push_failed(request):
    _LOGGER.info('order_withdraw_retry_push_failed order withdraw: %s',
                 request.body)
    order_withdraw_handler.retry_push_failed()
    return {'result': 'ok'}


@require_POST
@response_wrapper
def order_withdraw_auto_close(request):
    _LOGGER.info('order_withdraw_auto_close order withdraw: %s', request.body)
    params = json.loads(smart_unicode(request.body))
    check_params(
        params,
        ['order_id', 'card_code', 'status', 'notes', 'operating_time', 'sign'])

    params['operating_time'] = datetime.strptime(params['operating_time'],
                                                 '%Y-%m-%d %H:%M:%S')
    order_id = params['order_id']
    if order_withdraw_handler.check_valid_order(
            params, order_withdraw_handler.order_withdraw_finished):
        order_withdraw_db.edit_order(params)
        order_withdraw_handler.notify({'order_id': order_id})
    return {'result': 'ok'}


@require_POST
@response_wrapper
def order_withdraw_get_orders_for_exe(request):
    _LOGGER.info('order_withdraw_get_orders_for_exe order withdraw: %s',
                 request.body)
    params = json.loads(smart_unicode(request.body))
    check_params(params, ['card_id'])
    card_id = params['card_id']

    orders = order_withdraw_db.get_orders_for_exe(card_id)
    result = []
    for order in orders:
        order["operating_time"] = datetime.utcnow()
        result.append(order)
    return {'result': 'ok', 'list': result}


@require_POST
@response_wrapper
def test_auto_assign_new_card(request):
    order_withdraw_handler.auto_assign_new_card()
    return {'result': 'ok'}
